#!/usr/bin/env python
import SecureXMLRPCServer
import os.path
import rrd
import pickle
import sys

class Monitor:
	def __init__(self):
		# ensure paths exists
		self.datadir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')
		if not os.path.isdir(self.datadir):
			os.mkdir(self.datadir)

	def _clientKnown(self, ip):
		return os.path.isdir(os.path.join(self.datadir, ip))
		
	def _createClient(self, ip):
		os.mkdir(os.path.join(self.datadir, ip))

	def _isDataSetKnown(self, sname, ip, name):
		return os.path.isfile(os.path.join(self.datadir, ip, sname+'.'+name+'.rrd'))

	def _parseMuninData(self, data):
		# parse the incoming data now...
		# foobar.value 2
		result = []
		type = 'config'
		lines = data.splitlines()
		for line in lines:
			if line.strip() == '':
				continue
			args = line.split(' ', 1)
			args2 = args[0].split('.', 1)
			
			rargs = args2
			rargs.extend(args[1:])
			
			if len(rargs) == 3 and rargs[1] == 'value':
				type = 'value'
			result.append(rargs)
		return type, result

	def _extractDataSetName(self, data):
		result = []
		for line in data:
			if len(line) == 3 and (line[1] == 'value' or line[1] == 'label'):
				result.append(line[0])
		result.sort()
		return '_'.join(result)

	def _updateData(self, name, ip, data_string):
		type, data = self._parseMuninData(data_string)
		if type != 'value':
			# we wont allow config posts in here
			return 'error'
		if not self._clientKnown(ip):
			self._createClient(ip)

		dataset_name = self._extractDataSetName(data)
		if not self._isDataSetKnown(name, ip, dataset_name):
			print 'dataset unkown' + dataset_name + ', requesting config ...'
			return 'config'
		
		print 'updating dataset ' + dataset_name + ' ...'
		
		values = []
		for line in data:
			if line[1] == 'value':
				values.append(float(line[2]))
		
		rrdfn = os.path.join(self.datadir, ip, name+'.'+dataset_name+'.rrd')
		r = rrd.RRD(rrdfn)
		r.update(values)
		return 1
			
	def _configureData(self, sname, ip, data_string):
		type, data = self._parseMuninData(data_string)
		dataset_name = self._extractDataSetName(data)
		print 'creating dataset ' + dataset_name + ' ...'
		if not self._clientKnown(ip):
			self._createClient(ip)
		
		# prevent users to write data anywhere (thanks to soeren)
		name = os.path.basename(dataset_name)
		rrdfn = os.path.join(self.datadir, ip, sname+'.'+dataset_name+'.rrd')
		r = rrd.RRD(rrdfn)
		r.create_rrd(300, data) # 300 = 5 minutes
		f = open(rrdfn+'.config', "wb")
		pickle.dump(data, f)
		f.close()
		return 'created'

	def update(self, name, data):
		sys.stdout.write("new data from "+self.clientIP+"('"+name+"'): ")
		return self._updateData(name, self.clientIP, data)
	
	def config(self, name, data):
		sys.stdout.write("new CONFIG data from "+self.clientIP+"('"+name+"'): ")
		return self._configureData(name, self.clientIP, data)

authmap = None #{ 'user':'password' }
server = SecureXMLRPCServer.SecureXMLRPCServer(("",8888), 'key.pem', 'cert.pem', authmap)
monitor = Monitor()

server.register_instance(monitor)

SecureXMLRPCServer.global_class_instance = monitor

print "server running"
server.serve_forever()
